from ConfigChecker import *
import subprocess
import threading
import os
import logging

# ===CODE===

# 【注意】详情参考develop.md第六节
# 只执行cmd，不管环境变量
# 环境变量应该写入cmd中

def run_cmd(cmd:str, capture_output=False, log_level=logging.DEBUG) -> subprocess.CompletedProcess:
    logging.log(log_level, '    ' + cmd)
    return subprocess.run(cmd, shell=True, capture_output=capture_output)

def run_cmds(cmds:list, capture_output=False, log_level=logging.DEBUG) -> list:
    '''最大并发执行多个cmd
    返回一个list，每个元素对应cmds中的cmd的运行结果'''
    class CommandTasks:
        '''各个线程从这个类获取要执行的cmd，线程安全'''
        def __init__(self, cmds):
            self.cmds = cmds
            self.cmd_idx = 0
            self.lock = threading.Lock()

        def get(self):
            '''获取一个cmd，成功返回(cmd_idx, cmd)，没有task时返回None'''
            ret = None
            self.lock.acquire()
            if self.cmd_idx < len(self.cmds):
                ret = (self.cmd_idx, self.cmds[self.cmd_idx])
                self.cmd_idx += 1
            self.lock.release()
            return ret

    class TaskThread(threading.Thread):
        '''用subprocess执行一个cmd'''
        def __init__(self, cmd_tasks:CommandTasks, capture_output):
            threading.Thread.__init__(self)
            self.cmd_tasks = cmd_tasks
            self.capture_output = capture_output
            self.ret = {}

        def run(self):
            while True:
                task = self.cmd_tasks.get()
                if task == None:
                    break
                cmd_idx, cmd = task
                logging.log(log_level, '    ' + cmd)
                one_ret = subprocess.run(cmd, shell=True, capture_output=self.capture_output)
                self.ret[cmd_idx] = one_ret

    thread_count = os.cpu_count()
    if len(cmds) < thread_count:
        thread_count = len(cmds)
    tasks = CommandTasks(cmds)
    all_result = [None] * len(cmds)
    threads = []
    # 创建并启动若干个线程，每个线程内启动subprocess同步执行cmd
    for _ in range(0, thread_count):
        t = TaskThread(tasks, capture_output)
        t.start()
        threads.append(t)
    # 等待所有线程结束，并且汇总运行结果
    for t in threads:
        t.join()
        for cmd_idx in t.ret:
            all_result[cmd_idx] = t.ret[cmd_idx]

    return all_result

def run_solution_build_cmds(cmds):
    pass

def run_cmd_dag(cmd_dag, capture_output=False) -> dict:
    '''最大并发执行有依赖关系的多个cmd'''
    pass